package com.mutouren.modules.org.service.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.mutouren.common.entity.PageInfo;
import com.mutouren.common.entity.Result;
import com.mutouren.common.entity.ResultCode;
import com.mutouren.common.entity.ResultInfo;
import com.mutouren.common.entity.ValidState;
import com.mutouren.common.orm.spring.BaseServiceImpl;
import com.mutouren.common.utils.DigestUtils;
import com.mutouren.common.utils.StringUtils;
import com.mutouren.modules.org.dao.OrganizationDao;
import com.mutouren.modules.org.dao.OrganizationPersonDao;
import com.mutouren.modules.org.dao.PersonDao;
import com.mutouren.modules.org.entity.IdentityType;
import com.mutouren.modules.org.model.Function;
import com.mutouren.modules.org.model.Organization;
import com.mutouren.modules.org.model.OrganizationPerson;
import com.mutouren.modules.org.model.Person;
import com.mutouren.modules.org.service.OrganizationService;
import com.mutouren.modules.org.service.PersonService;

@Service
public class PersonServiceImpl extends BaseServiceImpl<Person> implements PersonService {
	
	private static final String defaultPassword = "123456";
	private static final String md5PasswordFormat = "mtr%s%s";	
	
	@Resource
	private OrganizationService organizationService;	
	
	@Resource
	private PersonDao personDao;
	
	@Resource
	private OrganizationDao organizationDao;	
	
	@Resource
	private OrganizationPersonDao organizationPersonDao;	

	@Override
	public void afterPropertiesSet() throws Exception {
		this.baseDao = personDao;
	}
	
	@Override
	public Person get(Object personId) {		
		Person result = this.personDao.get(personId);
		if (result == null) return null;
		
		Organization org = this.organizationService.get(result.getOrgId()); 
		result.setOrgPath(org.getChineseAllPath());		
		return result;
	}
	
	@Override
	public ResultInfo<Person> login(String userName, String password) {
		ResultInfo<Person> result = new ResultInfo<Person>();
		result.setCode(ResultCode.FAIL.value);
		Person person = this.personDao.getByIdentity(buildLoginUser(userName));
		
		if ((person == null) || (person.getValidState() != ValidState.Normal)) {
			result.setMessage("登录名无效");
			return result;
		}
		
		String md5Password = DigestUtils.MD5(String.format(md5PasswordFormat, password, person.getSalt())); 
		if (!md5Password.equals(person.getPassword())) {
			result.setMessage("密码错误");
			return result;
		}
		
		this.personDao.updateLastLoginTime(person.getPersonId());
		
		result.setCode(ResultCode.SUCCESS.value);
		result.setInfo(person);
		return result;
	}
	
	private Person buildLoginUser(String loginName) {
		Person result = new Person();
		
		if (loginName.indexOf("@") >= 0) {
			result.setEmail(loginName);
		} else if (NumberUtils.isNumber(loginName) && loginName.length() == 11) {
			result.setMobile(loginName);
		} else {
			result.setLoginName(loginName);
		}
		
		return result;
	}	
	
	@Override
	public int modify(Person person) {
		try {
			return super.modify(person);
		} catch(DuplicateKeyException t) {
			throw new RuntimeException("用户名、邮箱、手机号，必须唯一"); 
		}		
	}
	
	@Override
	@Transactional
	public int add(Person person) {
		
		if (!isValidOrganization(person.getOrgId())) {
			throw new RuntimeException("组织状态非有效");
		}

		person.setSalt(new Random().nextInt(1000000));
		String md5Password = DigestUtils.MD5(String.format(md5PasswordFormat, defaultPassword, person.getSalt())); 
		person.setPassword(md5Password);	

		try {
			this.personDao.insert(person);
		} catch(DuplicateKeyException t) {
			throw new RuntimeException("用户名、邮箱、手机号，必须唯一"); 
		}
		
		return this.organizationPersonDao.insert(new OrganizationPerson(person.getOrgId(), 
				person.getPersonId()));
	}
	
	@Override
	public void resetPassword(int personId) {
		Person person = personDao.get(personId);
		String md5PasswordNew = DigestUtils.MD5(String.format(md5PasswordFormat, defaultPassword, person.getSalt()));
		personDao.modifyPassword(personId, md5PasswordNew);				
	}	

	@Override
	public Result modifyPassword(int personId, String oldPassword, String newPassword) {
		Result result = new Result();
		Person person = personDao.get(personId);
		if (person == null) {
			result.setCode(ResultCode.FAIL.value);
			result.setMessage("用户无效");
			return result;			
		}
		String md5PasswordOld = DigestUtils.MD5(String.format(md5PasswordFormat, oldPassword, person.getSalt()));
		if (!md5PasswordOld.equals(person.getPassword())) {
			result.setCode(ResultCode.FAIL.value);
			result.setMessage("原密码错误");
			return result;
		}
				
		String md5PasswordNew = DigestUtils.MD5(String.format(md5PasswordFormat, newPassword, person.getSalt()));
		personDao.modifyPassword(personId, md5PasswordNew);
		result.setCode(ResultCode.SUCCESS.value);
		return result;
	}
	
	@Override
	public int updateLastLoginTime(int personId) {
		return personDao.updateLastLoginTime(personId);
	}	

	@Override
	public void addToOrg(int orgId, int personId) {
		if (!isValidOrganization(orgId)) {
			throw new RuntimeException("目标组织状态非有效");
		}
		
		Person person = this.personDao.get(personId);
		OrganizationPerson op = this.organizationPersonDao.get(new OrganizationPerson(person.getOrgId(), personId));
		if(op.getValidState() != ValidState.Normal) {
			throw new RuntimeException("人员主岗状态非有效");
		}
		
		if (organizationPersonDao.get(new OrganizationPerson(orgId, personId)) == null) {
			organizationPersonDao.insert(new OrganizationPerson(orgId, personId));		
		}
	}

	@Override
	public void removeFromOrg(int orgId, int personId) {
		organizationPersonDao.delete(new OrganizationPerson(orgId, personId));		
	}

	@Override
	public List<Person> selectByOrgId(int orgId, boolean isOnlyMainPos, boolean isCascade, String searchName, PageInfo pageInfo) {
		if (searchName != null) {
			searchName = searchName.trim();
		}		
		
		Organization org = organizationService.get(orgId);		
		
		PageHelper.startPage(pageInfo.getPageIndex(), pageInfo.getPageSize(), true);
		List<Person> listPerson = organizationPersonDao.searchUser(orgId, org.buildSelfIdPath(), isOnlyMainPos, isCascade, searchName);
		com.github.pagehelper.Page<Person> page = (com.github.pagehelper.Page<Person>)listPerson;		
		pageInfo.setTotal((int)page.getTotal());		
		
		List<Organization> listOrganization = organizationService.getChildren(orgId, true, true, true, ValidState.Invalid);
		Map<Integer, Organization> mapOrganization = organizationService.toMap(listOrganization);
		for(Person obj : listPerson) {
			Organization objOrg = mapOrganization.get(obj.getRelateOrgId());
			if (objOrg != null) {
				obj.setRelateOrgPath(objOrg.getChineseAllPath());
			}
		}		
		return listPerson;
	}

	@Override
	@Transactional
	public void changeOrg(int personId, int oldOrgId, int newOrgId) {
		if (oldOrgId == newOrgId) return;
		
		if (!isValidOrganization(newOrgId)) {
			throw new RuntimeException("目标组织状态非有效");
		}		
		
		OrganizationPerson op = this.organizationPersonDao.get(new OrganizationPerson(newOrgId, personId));
		if (op != null) {
			throw new RuntimeException("转到组织已存在该人员");
		}
		
		Person person = this.personDao.get(personId);
		boolean isMainPosition = person.getOrgId() == oldOrgId;
		if (isMainPosition) {
			this.personDao.setMainPosition(personId, newOrgId);
		}

		organizationPersonDao.insert(new OrganizationPerson(newOrgId, personId));	
		organizationPersonDao.delete(new OrganizationPerson(oldOrgId, personId));
	}

	@Override
	public List<Organization> selectPosition(int personId) {
		List<Organization> result = this.organizationPersonDao.selectPosition(personId);
		this.organizationService.loadChinesePath(result);
		return result;
	}

	@Override
	public void setMainPosition(int personId, int orgId) {
		this.personDao.setMainPosition(personId, orgId);		
	}

	@Override
	public int setState(Person person) {
		throw new RuntimeException("not permit call the setState(Person person)");
	}
	
	@Override
	@Transactional
	public int setState(OrganizationPerson op) {
		OrganizationPerson tempOp = this.organizationPersonDao.get(op);
		if (tempOp.getValidState() == op.getValidState()) {
			throw new RuntimeException("与当前状态一致，不处理");
		}
				
		Person person = this.personDao.get(op.getPersonId()); 
		boolean isMainPosition = person.getOrgId() == op.getOrgId();
		
		if (op.getValidState() == ValidState.Normal) {
			return setState_Normal(op, person, isMainPosition);
		} else {
			return setState_InvalidOrDelete(op, person, isMainPosition);
		}		
	}
	
	private int setState_Normal(OrganizationPerson op, Person person, boolean isMainPosition){
		if (isMainPosition) {
			return this.organizationPersonDao.setState(op);
		} else {
			OrganizationPerson opMain = this.organizationPersonDao.get(new OrganizationPerson(person.getOrgId(), person.getPersonId()));
			if (opMain.getValidState() != ValidState.Normal) {
				throw new RuntimeException("人员主岗状态非有效");
			}
			return this.organizationPersonDao.setState(op);		
		}
	}
	
	private int setState_InvalidOrDelete(OrganizationPerson op, Person person, boolean isMainPosition){
		if (isMainPosition) {
			return this.organizationPersonDao.setStateByPersonId(op);
		} else {
			return this.organizationPersonDao.setState(op);
		}
	}	
	
	private boolean isValidOrganization(int orgId) {
		Organization org = this.organizationService.get(orgId);
		return org.getValidState() == ValidState.Normal;
	}

	@Override
	public List<Function> selectFunction(int personId, int appId) {
		List<Organization> listOrg = this.organizationPersonDao.selectPosition(personId);
		if (listOrg.size() == 0) {
			return new ArrayList<Function>();
		}
		
		Set<Integer> setOrgId = getAllParentOrSelfOrgId(listOrg);
		return this.organizationPersonDao.searchFuncByOrgIds(appId, setOrgId);
	}
	
	private Set<Integer> getAllParentOrSelfOrgId(List<Organization> listOrg) {
		Set<Integer> setOrgId = new HashSet<Integer>();
		
		for(Organization org : listOrg) {
			//if (org.getParentId() == Organization.ROOT_ID) continue;
			
			List<Integer> ids = StringUtils.toListInteger(org.getSelfIdPath(), Organization.PATH_SEPARATOR);
			for(Integer id : ids) {
				if (!setOrgId.contains(id)) {
					setOrgId.add(id);
				}
			}
		}
		
		return setOrgId;
	}

	@Override
	public Person getByIdentity(String identity, IdentityType identityType) {
		Person person = new Person();
		switch(identityType) {
		case loginName:
			person.setLoginName(identity); break;
		case email:
			person.setEmail(identity); break;
		case mobile:	
			person.setMobile(identity);break;
		}
		
		return this.personDao.getByIdentity(person);
	}	

}
